Imports System.IO
Imports cmplib01
Imports FMPLib01
Imports System.Drawing
Imports System.Windows
Imports System.Windows.Forms
Imports ICombatEngine


Public Class ConquestCombatEngine
    Implements ICombatEngine.ICombatEngine


    Private Const c_Module As String = "ConquestCombatEngine"
    Private Const c_MaxChitDetectionLevel As Integer = 12
    Private Const c_RoadDistance As Integer = 5

    Private Structure Boiler
        Public Chit As ChitMember
        Public Location As PointF
        Public TerrainMod As Single
        Public Size As Single
        Public LosPower As Single
        Public LosRange As Long
        Public Detected As Boolean
        Public OwningFactionKey As String
        Public OwningPlayerID As Integer
        Public ZOCRange As Integer
    End Structure

    Private Enum OnRoadType
        NoRoad = 0
        UnimprovedRoad = 1
        ImprovedRoad = 2
        MajorRoad = 3
    End Enum


    Public Event PercentComplete(ByVal percent As Integer)

    Private m_UsesContactCombat As Boolean = True
    Private m_UsesRangedCombat As Boolean = False
    Private m_UsesPreCombatWindow As Boolean = True
    Private _currentPhase As Integer = 0
    Private _executedPhases As Integer

    'Private contactRange As Int16 = 16 ' this is for determining if two units are touching
    Private joinCombatDistance As Int16 = 16   ' this is for determining if a new combat should be made, or if to add the targets in question to 
    '                                                              an existing combat.
    '                                                              this should be the 'combat range' defined in the campaign

    Private ptrGameData As cmplib01.CampaignerGameData
    Private ptrFMPData As FMPLib01.FlexMapData

    Private arrDistance(10, 10) As Single ' used for distance between chits
    Private arrFactionA(1) As Boiler
    Private arrFactionB(1) As Boiler

    Private detectionHalt As Boolean = False    '// once a unit is NEWLY detected, we HALT the turn there. 
    Private dhr As Integer '// the reason for the "detection halt", usually is 0 for an actual detection halt, but when its 120, there's an auth key problem

    Private _pixelsPerOneMile As Single
    Private turnMultiplier As Single  ' used to get the correct speed of a unit

    Private _phaseCount As Integer

    Private _LOSDegredationAmount As Single = 5

    Private randy As New Random


    Public Property LOSDegredationAmount() As Single
        Get
            Return _LOSDegredationAmount
        End Get
        Set(ByVal value As Single)
            _LOSDegredationAmount = value
        End Set
    End Property

    Public Property pixelsPerOneMile() As Single
        Get
            Return _pixelsPerOneMile
        End Get
        Set(ByVal value As Single)
            _pixelsPerOneMile = value
        End Set
    End Property

    Public ReadOnly Property ExecutedPhases() As Integer
        Get
            Return _executedPhases
        End Get

    End Property

    Public Function CombatReportString() As String Implements ICombatEngine.ICombatEngine.CombatReportString
        ' this returns a combat report in string format
        Return ""
    End Function

    Public Function CombatReportXML() As System.Xml.XmlDataDocument Implements ICombatEngine.ICombatEngine.CombatReportXML
        ' this returns as combat report in xml format
        Return New Xml.XmlDataDocument()
    End Function

    Public Function Combats() As cmplib01.Battles Implements ICombatEngine.ICombatEngine.Combats
        Return Nothing
    End Function

    Private Function calculateValues() As Boolean
        Try
            '            Dim res As Boolean
            '            Dim ht As New Hashtable

            '            For Each key As String In ptrGameData.Players.Keys
            '                Dim play As Player = ptrGameData.Players.Item(key)
            '                'param1 is the authentication key
            '                'param2 is the computer name
            '                'if the authentication key exists already, the computer name had better be the same... kind of lame checking, but there it is.
            '#If DEBUG Then
            '                Debug.WriteLine(play.param1 & ": " & play.param2)
            '#End If

            '                If ht.Item(play.param1) Is Nothing Then
            '                    ht.Add(play.param1, play.param2)
            '                Else
            '                    ' the key already exists
            '                    dhr = 120
            '                    '// now, the computer names should be the same, if so, ignore 
            '                    If ht.Item(play.param1) <> play.param2 Then
            '                        If play.param1 <> "xxxxxx-xxxx-xxxx-xxxxxx" Then
            '                            detectionHalt = True
            '                            Return True
            '                        End If
            '                    End If
            '                End If
            '            Next

            For Each gp As GenericProperty In ptrGameData.ExtendedProperties
#If DEBUG Then
                Debug.WriteLine("found: " & gp.PropertyValue)
#End If
            Next

            Return True

        Catch ex As Exception
            HandleException("campaignerCombatEngineB.cm", ex)
        End Try
    End Function

    Public Sub GenerateCombatTurn(ByRef gameData As cmplib01.CampaignerGameData) Implements ICombatEngine.ICombatEngine.GenerateCombatTurn
        Try
            ptrGameData = gameData

            Dim skipBit As Byte = 0
            Dim skipBitStop As Integer = 0 'PhaseCount / 10
            Dim FactA As cmplib01.Faction
            Dim fukov As String
            Dim a As Int16 ' faction a in arrfactiona boiler
            Dim b As Int16
            Dim removeCollection As New Collection
            Dim phaseLength As TimeSpan
            Dim calculated As Boolean

            calculated = calculateValues()   '// doesn't really calculate any values, it checks the keys to make sure there's no dupe's.

            For Each fukov In ptrGameData.Faction_g.HT.Keys
                FactA = ptrGameData.Faction_g.Item(fukov)
                ' The first faction is faction a
                Exit For
            Next

            ResetBoiler()
            PopulateBoiler()

            '// calculate all BG properties
            CalculateProperties()
            ResetInvalidWaypoints()

            If ptrGameData.combatEngagementRange = 0 Then ptrGameData.combatEngagementRange = 8

            '// figure out our time increment, and number of phases
            Select Case gameData.TurnLength
                Case TurnLength_cgd.FiveMinute
                    phaseLength = New TimeSpan(0, 0, 6)
                    turnMultiplier = 0.08
                    _phaseCount = 50
                Case TurnLength_cgd.FifteenMinute
                    phaseLength = New TimeSpan(0, 0, 18)
                    turnMultiplier = 0.25
                    _phaseCount = 50
                Case TurnLength_cgd.HalfHour
                    phaseLength = New TimeSpan(0, 0, 36)
                    turnMultiplier = 0.5
                    _phaseCount = 50
                Case TurnLength_cgd.Hour
                    phaseLength = New TimeSpan(0, 1, 12)
                    turnMultiplier = 1
                    _phaseCount = 50
                Case TurnLength_cgd.HalfDay
                    phaseLength = New TimeSpan(0, 14, 16)
                    turnMultiplier = 6
                    _phaseCount = 50
                Case TurnLength_cgd.FullDay
                    phaseLength = New TimeSpan(0, 30, 0)
                    turnMultiplier = 1   '// full day forces daily movement rate. haha
                    _phaseCount = 48
                Case TurnLength_cgd.Week
                    phaseLength = New TimeSpan(0, 210, 0)
                    turnMultiplier = 7
                    _phaseCount = 48
                Case TurnLength_cgd.Month
                    phaseLength = New TimeSpan(0, 900, 0)
                    turnMultiplier = 30
                    _phaseCount = 48
            End Select

            For Each mem As ChitMember In gameData.Chits
                If mem.UnitType = GroundChitClass_cgd.Battlegroup Then SetEffectiveSpeed(mem)
            Next

            ' MOVEMENT
            For _currentPhase = 0 To _phaseCount - 1
                Application.DoEvents()
                '// decrement timeremaining, increment elapsedtime
                gameData.ElapsedTime = gameData.ElapsedTime.Add(phaseLength)
                gameData.remainingTime = gameData.remainingTime.Subtract(phaseLength)

                gameData.globalPhaseCount += 1

                If gameData.ReplayPhaseKeysCol Is Nothing Then gameData.ReplayPhaseKeysCol = New Collection
                gameData.ReplayPhaseKeysCol.Add(gameData.ElapsedTime.ToString, "g-" & gameData.globalPhaseCount)

                Try
                    RaiseEvent PercentComplete(((_currentPhase + 1) / _phaseCount) * 100)
                Catch
                End Try

                ' reset boiler faction counters
                a = 0
                b = 0

                '// clear "detected this phase"
                For Each mem As ChitMember In ptrGameData.Chits
                    '// insert the historical entry, update it later
                    Dim histo As New HistoricalEntry
                    If mem.playbackEntries Is Nothing Then mem.playbackEntries = New HistoricalEntries

                    mem.playbackEntries.add(gameData.ElapsedTime.ToString, histo)

                    Select Case mem.UnitType

                        Case GroundChitClass_cgd.Battlegroup
                            Dim batt As BattlegroupChit = mem
                            '// ZOC for all
                            ZOCBehavior(batt)

                            '// we only care about units that CAN move
                            Select Case batt.Status
                                Case GroundUnitStatus_cgd.OK, GroundUnitStatus_cgd.Moving, GroundUnitStatus_cgd.Regrouped
                                    MoveUnit2(batt, _phaseCount)
                                    If batt.OwningFaction.FactionID = FactA.FactionID Then
                                        arrFactionA(a).Location = New Point(batt.Location.X, batt.Location.Y)
                                    Else
                                        arrFactionB(b).Location = New Point(batt.Location.X, batt.Location.Y)
                                    End If

                                    '// contact check
                                    ContactCheck(batt, _currentPhase)
                            End Select
                    End Select

                    '// update historical position.
                    histo.location = mem.Location
                    histo.detectionStatus = mem.detectionLevelThisTurn
                    histo.unitStatus = mem.Status
                Next mem

                ' DETECTION - this is the actual detection check.
                PointToPointBoiler()

                '// here we do the trespassing
                TrespassingTest()

                ' AREA OBJECTIVES
                AreaObjectiveOwnership()
                AssignAOownership()

                ' HALT ON NEW DETECTION
                If ptrGameData.haltOnNewDetection = True Then
                    If gameData.Turn > 1 Then     '// no halts occur during the first turn. Whaazzzzaaaa!
                        If detectionHalt = True Then
                            detectionHalt = False
                            Exit For
                        End If
                    End If
                End If

                '// there is a elapsedtime end halt check too...
                If gameData.remainingTime <= TimeSpan.Zero Then
                    Exit For
                End If
                ' dease those that haven't been seen this phase

                DecreaseDetectionForUnspotted()

                '// in the conquest engine, we handle combat a little differently. 
                ConquestCombat()

            Next ' Phase Count

            _executedPhases = _currentPhase


            ' TITANIC CHITS
            ' titanic objects now get a +1 detection. This means that an 'unspotted' one will always have a question mark until a unit is close enough to see it.
            IncreaseDetectionForTitanicObjects()

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.GenerateTurn", ex)
        End Try
    End Sub

    Private Sub resetDetection()
        Try

            For Each mem As ChitMember In ptrGameData.Chits
                mem.detectedThisPhase = False
            Next

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Private Sub CalculateProperties()
        Try
            For Each mem As ChitMember In ptrGameData.Chits
                If mem.UnitType = GroundChitClass_cgd.Battlegroup Then DirectCast(mem, BattlegroupChit).calculateProperties()
            Next
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Private Sub TrespassingTest()
        Try

            For Each mem As ChitMember In ptrGameData.Chits
                For Each key As String In ptrGameData.DeploymentZones_g.HT.Keys
                    Dim zone As DeploymentZone = ptrGameData.DeploymentZones_g.Item(key)
                    If Not zone.FactionID.Equals(mem.OwningFaction.FactionID) Then
                        If IsChitWithin(zone, mem) Then zone.Trespassed = True
                    End If
                Next
            Next

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.TrespassingTest", ex)
        End Try
    End Sub

    Private Sub PreGameDPContest()
        Try

            For Each mem As ChitMember In ptrGameData.Chits

                For Each key As String In ptrGameData.DeploymentZones_g.HT.Keys
                    Dim zone As DeploymentZone = ptrGameData.DeploymentZones_g.Item(key)
                    If Not zone.FactionID.Equals(mem.OwningFaction.FactionID) Then
                        If IsChitWithin(zone, mem) Then
                            zone.Trespassed = True
                            zone.Contested = True
                            If zone.Capturable Then
                                '// in the pregame contest, we will only obey HOLD capture events, there's no sense in any other option
                                If zone.CaptureEvent = CaptureEvent_cgd.Hold Then
                                    zone.Captured = True
                                End If
                            End If
                        End If

                    End If
                Next
            Next

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.PreGameDPContest", ex)
        End Try
    End Sub

    Private Sub IncreaseDetectionForTitanicObjects()

        For Each mem As ChitMember In ptrGameData.Chits
            If mem.Size >= 1500 Then
                mem.detectionLevelThisTurn += _LOSDegredationAmount
                mem.detectedThisPhase = True
            End If
        Next

    End Sub

    Private Sub AreaObjectiveOwnership()

        Dim ao As AreaObjective

        '// Faction A is the first faction, Faction B is the second
        '// reset the area objective information first.
        ResetAOInfo()

        Try
            For Each mem As ChitMember In ptrGameData.Chits
                If mem.Status <> GroundUnitStatus_cgd.Dead Then
                    For Each ao In ptrGameData.AreaObjectives
                        If ao.ObjectiveRegion.IsVisible(mem.Location) Then
                            If Not ao.FactionsPresent.Contains(mem.OwningFaction) Then
                                ao.FactionsPresent.Add(mem.OwningFaction)
                            End If
                        End If
                    Next
                End If
            Next

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Sub ResetAOInfo()
        Dim ao As AreaObjective
        For Each ao In ptrGameData.AreaObjectives
            ao.FactionsPresent = New ArrayList
        Next
    End Sub

    Private Sub AssignAOownership()
        Dim ao As AreaObjective
        For Each ao In ptrGameData.AreaObjectives
            Select Case ao.FactionsPresent.Count
                Case Is = 0
                Case Is = 1
                    ao.OwningFaction = ao.FactionsPresent.Item(0).factionid
                    ao.IsContested = False
                Case Else
                    ao.IsContested = True
            End Select
        Next
    End Sub

    Private Sub ZOCBehavior(ByRef unit As BattlegroupChit)
        Dim closestDistance As Integer = 500000
        Dim distance As Integer
        Dim validEnemy As Boiler
        Dim factA As Faction
        Dim factAkey As String
        Dim enemyBoil() As Boiler
        Dim bInZOC As Boolean
        'Dim newWap As New Point

        '// find out which boiler array we need to use
        '// factionA array is the first found faction in the collection

        Try
            For Each factAkey In ptrGameData.Faction_g.HT.Keys
                factA = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction.FactionID)
                Exit For
            Next

            If factAkey = ptrGameData.CDGKEY_FACTION & unit.OwningFaction.FactionID Then
                enemyBoil = arrFactionB
            Else
                enemyBoil = arrFactionA
            End If

            Dim this As Boiler
            For Each this In enemyBoil

                Select Case this.Chit.Status
                    Case GroundUnitStatus_cgd.Dead, GroundUnitStatus_cgd.Disarrayed, GroundUnitStatus_cgd.Assembling, GroundUnitStatus_cgd.Not_Deployed, GroundUnitStatus_cgd.Regrouping, GroundUnitStatus_cgd.Scattered
                        '// does not use its ZOC...

                    Case GroundUnitStatus_cgd.OK, GroundUnitStatus_cgd.Regrouped, GroundUnitStatus_cgd.Moving
                        '// use full
                        distance = XYDistance(unit.PreciseLocation, this.Chit.PreciseLocation)
                        '// 1.0.2.4 added combatEngagementRange to ZOC range.
                        If (distance < closestDistance) AndAlso (distance <= this.ZOCRange + ptrGameData.combatEngagementRange) Then
                            validEnemy = this
                            closestDistance = distance
                            bInZOC = True
                        End If
                    Case GroundUnitStatus_cgd.Engaged, GroundUnitStatus_cgd.Reinforcing
                        '// use HALF, unless it's an installation, which ALWAYS use their full ZOC, no matter whatsie.
                        distance = XYDistance(unit.PreciseLocation, this.Chit.PreciseLocation)
                        Dim zocRange As Single = 0
                        If this.Chit.UnitType <> GroundChitClass_cgd.Objective Then
                            zocRange = this.ZOCRange / 2
                        Else
                            zocRange = this.ZOCRange
                        End If
                        '// now check it! :D
                        If (distance < closestDistance) AndAlso (distance <= (zocRange)) Then
                            validEnemy = this
                            closestDistance = distance
                            bInZOC = True
                        End If
                End Select
            Next

            '// now behave!
            If Not bInZOC Then Exit Sub
            Dim thisFact As Faction

            If unit.OwningFaction.FactionID = factA.FactionID Then
                thisFact = factA
            Else
                thisFact = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction.FactionID)
            End If

            Dim target As ChitMember = validEnemy.Chit
            IncreaseDetectionOnTarget(thisFact, target)

            Select Case unit.order
                Case Is = "Engage"
                    unit.waypoints.Clear()

                    Dim newwap As New SmartWaypoint
                    newwap.LOC = validEnemy.Chit.Location
                    newwap.OrderText = "Engage"
                    newwap.Speed = unit.movementSpeed
                    unit.waypoints.add(newwap)

                    SetEffectiveSpeed(unit)

                Case Is = "Withdraw"
                    unit.waypoints.Clear()

                    Dim newwap As New SmartWaypoint
                    newwap.LOC = New Point(validEnemy.Chit.PreciseLocation.X, validEnemy.Chit.PreciseLocation.Y)
                    newwap.OrderText = "Withdraw"
                    newwap.Speed = unit.movementSpeed

                    Dim xStr As Single
                    Dim yStr As Single
                    GetXYStrength(unit.PreciseLocation, validEnemy.Chit.PreciseLocation, xStr, yStr)
                    If validEnemy.ZOCRange + ptrGameData.combatEngagementRange >= closestDistance Then
                        newwap.LOC = New Point(validEnemy.Chit.PreciseLocation.X - (xStr * (closestDistance * 2.2)), validEnemy.Chit.PreciseLocation.Y - (yStr * (closestDistance * 2.2)))
                        '// the waypoint is only added if the group is within ZOC+CR range
                        unit.waypoints.add(newwap)
                    End If

                    SetEffectiveSpeed(unit)
                Case Else
                    '// clear all waypoints
                    unit.waypoints.Clear()
            End Select
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Function MoveUnit(ByRef unit As BattlegroupChit, ByVal phaseCount As Short) As Boolean
        Dim moveCost As Single
        Dim moveModifier As Single
        Dim speed As Single
        Dim newLocation As New Point
        Dim wap As SmartWaypoint
        Dim roadBonus As Single
        Dim sm As New SMVector
        Dim dailyRate As Single = 1

        Try
            Select Case unit.Status
                Case GroundUnitStatus_cgd.Moving
                Case GroundUnitStatus_cgd.OK
                Case Else
                    Return False '// we're not ok to move.
            End Select

            If unit.waypoints.Count = 0 Then
                unit.Status = GroundUnitStatus_cgd.OK
                unit.moveRemaining = 0
                Return False
            End If

            If unit.moveRemaining <= 0 Then
                unit.Status = GroundUnitStatus_cgd.OK
                unit.moveRemaining = 0
                Return False
            End If

            '// Road bonus
            Select Case PointIsOnRoad(New Point(unit.Location.X, unit.Location.Y))
                Case OnRoadType.NoRoad : roadBonus = 1
                Case OnRoadType.UnimprovedRoad : roadBonus = 1.3
                Case OnRoadType.ImprovedRoad : roadBonus = 1.5
                Case OnRoadType.MajorRoad : roadBonus = 1.7
            End Select

            '// this is either miles per day or miles per hour. per phase
            speed = unit.effectiveSpeed / phaseCount

            speed *= roadBonus
            moveModifier = ptrFMPData.MovementCost(New Point(unit.Location.X, unit.Location.Y), unit.movementClassID) * 0.01
            moveCost = moveModifier

            speed *= moveCost

            If speed >= 3 Then
                unit.moveAccumulated = speed
            Else
                unit.moveAccumulated += speed
            End If

            If unit.moveAccumulated >= 3 Then
                speed = unit.moveAccumulated
                unit.moveAccumulated = 0
            Else
                speed = 0
            End If

            '// get next coordinate (not using THIS crapola though-ola
            wap = unit.waypoints(0)

            Dim newLocationF As PointF = sm.GeneratePtOnVector(New PointF(unit.Location.X, unit.Location.Y), New PointF(wap.LOC.X, wap.LOC.Y), speed)

            newLocation.X = newLocationF.X
            newLocation.Y = newLocationF.Y

            '// check distance to end of waypoint
            If XYDistance(unit.Location, wap.LOC) <= XYDistance(unit.Location, newLocation) Then
                '// the waypoint is closer
                newLocation.X = wap.LOC.X
                newLocation.Y = wap.LOC.Y
                unit.waypoints.RemoveAt(0)
                '// get the next order, if there is one.
                If unit.waypoints.Count > 0 Then unit.order = unit.waypoints.item(0).OrderText
                '// now reset the speed so it's obeyed.
                SetEffectiveSpeed(unit)

            End If

            '// check to make sure we are moving into terrain that the movement class can
            If ptrFMPData.MovementAllowed(newLocation, unit.movementClassID) = False Then
                '// check for bridges? bridges allow a unit to move over 'Impassable' terrain. If you were to put a bridge
                '// across the top of a stinking mountain, then you would be able to cross the mountain. I suppose the 
                '// word TUNNEL should be used instead!
                '// Flexmap should do this for us. Shouldn't it?
                unit.invalidWaypoint = True
                Return False
            End If

            '// hmmn... roads?
            If speed > 0 Then unit.distanceTravelled += (speed + speed * moveCost) / roadBonus

            unit.Location = newLocation

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.MoveUnit2", ex)
        End Try
    End Function

    Private Function MoveUnit2(ByRef unit As BattlegroupChit, ByVal PhaseCount As Short) As Boolean
        Dim moveCost As Single
        Dim moveModifier As Single
        Dim speed As Single
        Dim newLocation As New PointF
        Dim wap As SmartWaypoint
        Dim roadBonus As Single
        Dim sm As New SMVector
        Dim dailyRate As Single = 1

        Try
            Select Case unit.Status
                Case GroundUnitStatus_cgd.Moving
                Case GroundUnitStatus_cgd.OK
                Case Else
                    Return False '// we're not ok to move.
            End Select

            If unit.waypoints.Count = 0 Then
                If unit.Status = GroundUnitStatus_cgd.Moving Then unit.Status = GroundUnitStatus_cgd.OK
                unit.moveRemaining = 0
                Return False
            End If

            If unit.moveRemaining <= 0 Then
                If unit.Status = GroundUnitStatus_cgd.Moving Then unit.Status = GroundUnitStatus_cgd.OK
                unit.moveRemaining = 0
                Return False
            End If

            '// Road bonus
            Select Case PointIsOnRoad(New Point(unit.PreciseLocation.X, unit.PreciseLocation.Y))
                Case OnRoadType.NoRoad : roadBonus = 1
                Case OnRoadType.UnimprovedRoad : roadBonus = 1.3
                Case OnRoadType.ImprovedRoad : roadBonus = 1.5
                Case OnRoadType.MajorRoad : roadBonus = 1.7
            End Select

            '// this is either miles per day or miles per hour. per phase
            speed = unit.effectiveSpeed / PhaseCount

            speed *= roadBonus
            moveModifier = ptrFMPData.MovementCost(New Point(unit.PreciseLocation.X, unit.PreciseLocation.Y), unit.movementClassID) * 0.01
            moveCost = moveModifier

            speed *= moveCost

            If speed >= 3 Then
                unit.moveAccumulated = speed
            Else
                unit.moveAccumulated += speed
            End If

            If unit.moveAccumulated >= 3 Then
                speed = unit.moveAccumulated
                unit.moveAccumulated = 0
            Else
                speed = 0
            End If

            '// get next coordinate (not using THIS crapola though-ola
            wap = unit.waypoints(0)

            Dim newLocationF As PointF = sm.GeneratePtOnVector(New PointF(unit.PreciseLocation.X, unit.PreciseLocation.Y), New PointF(wap.LOC.X, wap.LOC.Y), speed)

            newLocation.X = newLocationF.X
            newLocation.Y = newLocationF.Y

            '// check distance to end of waypoint
            If XYDistance(unit.Location, wap.LOC) <= XYDistance(unit.Location, newLocation) Then
                '// the waypoint is closer
                newLocation.X = wap.LOC.X
                newLocation.Y = wap.LOC.Y
                unit.waypoints.RemoveAt(0)
                '// get the next order, if there is one.
                If unit.waypoints.Count > 0 Then unit.order = unit.waypoints.item(0).OrderText
                '// now reset the speed so it's obeyed.
                SetEffectiveSpeed(unit)

            End If

            '// check to make sure we are moving into terrain that the movement class can
            If ptrFMPData.MovementAllowed(New Point(newLocation.X, newLocation.Y), unit.movementClassID) = False Then
                '// check for bridges? bridges allow a unit to move over 'Impassable' terrain. If you were to put a bridge
                '// across the top of a stinking mountain, then you would be able to cross the mountain. I suppose the 
                '// word TUNNEL should be used instead!
                '// Flexmap should do this for us. Shouldn't it?
                unit.invalidWaypoint = True
                Return False
            End If

            '// hmmn... roads?
            If speed > 0 Then unit.distanceTravelled += (speed + speed * moveCost) / roadBonus

            unit.PreciseLocation = newLocation

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.MoveUnit2", ex)
        End Try

    End Function

    Private Function PointIsOnRoad(ByRef hitPt As Point) As OnRoadType
        '// returns true if the hit point is within tolerance range of any road.
        Dim pt1 As Point
        Dim vx As Single
        Dim vy As Single
        Dim bOutOfRange As Boolean

        '\\equation of the line
        'm = dy/dx
        'y = mx + b
        'a = x intercept
        'b = y intercept
        'ax + by + c = 0

        Dim roadie As Road

        For Each roadie In ptrFMPData.Roads
            pt1.X = roadie.X1
            pt1.Y = roadie.Y1
            vx = roadie.X2 - roadie.X1
            vy = roadie.Y2 - roadie.Y1
            ' check to see if the vectors point in the same or different directions
            If (DistPointToLine(hitPt.X, hitPt.Y, 0, pt1.X, pt1.Y, 0, vx, vy, 0, bOutOfRange)) < c_RoadDistance Then
                If Not bOutOfRange Then
                    Select Case roadie.RoadType
                        Case FlexMapData.RoadType.ImprovedRoad : Return OnRoadType.ImprovedRoad
                        Case FlexMapData.RoadType.MajorRoad : Return OnRoadType.MajorRoad
                    End Select
                End If
            End If
        Next

        Return OnRoadType.NoRoad

    End Function

    Private Sub PointToPointBoiler()
        Dim a As Integer
        Dim b As Integer
        'Dim DetectingFaction As Faction
        Dim DetectingChit As ChitMember
        Dim TargetChit As ChitMember
        Dim dist As Integer

        '// wow. all in one loop instead of two. Schweet. That should take 1/2 the amount of time!
        Try
            For a = 0 To arrFactionA.GetUpperBound(0)
                For b = 0 To arrFactionB.GetUpperBound(0)
                    '// the distance between the two is the same of course
                    dist = XYDistance(arrFactionA(a).Chit.Location, arrFactionB(b).Chit.Location)
                    '// do a vs b
                    If Not arrFactionB(b).Detected Then
                        DetectingChit = arrFactionA(a).Chit
                        TargetChit = arrFactionB(b).Chit
                        BaseDetection(arrFactionA(a), DetectingChit, TargetChit, dist)
                    End If

                    '// do b vs a
                    If Not arrFactionA(a).Detected Then
                        DetectingChit = arrFactionB(b).Chit
                        TargetChit = arrFactionA(a).Chit
                        BaseDetection(arrFactionB(b), DetectingChit, TargetChit, dist)
                    End If
                Next
            Next
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Private Sub BaseDetection(ByRef detectingBoiler As Boiler, ByRef detectingChit As ChitMember, ByRef targetChit As ChitMember, ByVal dist As Long)
        Try

            If detectingBoiler.Chit.Status = GroundUnitStatus_cgd.Dead Then Exit Sub

            If dist <= detectingBoiler.LosRange Then
                '// check simple detection
                If DetectionCheck(detectingChit, targetChit) = True Then
                    '// this means detected? huh?
                    handleDetection(detectingChit.OwningFaction, targetChit, False)
                End If
                '// check p2p detection
                PointToPointDetection(detectingChit, targetChit, detectingChit.OwningFaction)
            End If

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Private Sub BaseDetectionSimple(ByRef detectingBoiler As Boiler, ByRef detectingChit As ChitMember, ByRef targetChit As ChitMember, ByVal dist As Long)
        Try

        Catch ex As Exception

        End Try
    End Sub

    Private Sub PointToPointDetection(ByRef DetectingChit As ChitMember, ByRef TargetChit As ChitMember, ByRef DetectingFaction As Faction)
        '// this is the point to point, meaning that the distance directly from one chit to the target chit is calculated
        '// it will short-circuit if the detecting chit "runs out" of range. Execution should only get here IF detection is
        '// a possibility. If the units are too far away to even detect each other, we shouldn't get here.
        '// we never count the point from origin.

        Dim MoveStep As Integer = 5
        Dim TotalCost As Single
        Dim done As Boolean
        Dim LOSCost As Single
        Dim i As Integer
        Dim samplepoint As PointF
        Dim sm As New SMVector
        'Dim diff As Single

        Dim losRangeInPixels As Integer = DetectingChit.LOS * (ptrFMPData.PixelsPerOneMile)

        '// we'll adjust for size baby!
        'MIXEDMODE is the new detection mode. We don't adjust for size or power in that mode.
        '           if the target is in the zone shown, he is spotted. Period.
        '           if mixedmode is off (0) then we calculate using power and target size.
        '#If MIXEDMODE = 0 Then
        '    losRangeInPixels *= (TargetChit.Size / 100)
        '#End If

        Dim rangeToTarget As Integer = XYDistance(DetectingChit.Location, TargetChit.Location)
        Dim currentSampleDistance As Integer

        Try

            Do Until done
                i += MoveStep
                samplepoint = sm.GeneratePtOnVector(New PointF(DetectingChit.Location.X, DetectingChit.Location.Y), New PointF(TargetChit.Location.X, TargetChit.Location.Y), i)

                LOSCost = ptrFMPData.LOSCost(New Point(samplepoint.X, samplepoint.Y))

                '#If MIXEDMODE = 0 Then
                '    '// adjust for LOS Power!! POWER POWER POWER!!
                '    If LOSCost > 1 Then
                '        diff = LOSCost - 1
                '        diff *= (DetectingChit.LOSPower / 100)
                '        LOSCost = diff + 1
                '        If LOSCost < 1 Then LOSCost = 1
                '    End If
                '#End If

                TotalCost += MoveStep * LOSCost

                currentSampleDistance = XYDistance(New Point(samplepoint.X, samplepoint.Y), DetectingChit.Location)
                If currentSampleDistance >= rangeToTarget Then
                    '// detected
                    handleDetection(DetectingFaction, TargetChit, False)
                    done = True
                End If

                If TotalCost >= losRangeInPixels / 2 Then
                    '// not so detected
                    done = True
                End If
            Loop

        Catch ex As Exception
            HandleException("Campaigner Combat Engine.PointToPointDetection", ex)
        End Try

    End Sub

    Private Sub LOSBoiler()
        ' this sub crunches the data 
        Dim a As Integer
        Dim b As Integer
        Dim SomeFact As cmplib01.Faction
        Dim SomeChit As ChitMember

        For a = 0 To arrFactionA.GetUpperBound(0)
            For b = 0 To arrFactionB.GetUpperBound(0)
                ' check against faction b, if not already detected this turn
                If arrFactionB(b).Detected = False Then
                    If LOSCheck(arrFactionA(a), arrFactionB(b)) = True Then
                        arrFactionB(b).Detected = True
                        ' find this newly targeted chit
                        SomeChit = arrFactionB(b).Chit
                        SomeFact = arrFactionA(a).Chit.OwningFaction
                        IncreaseDetectionOnTarget(SomeFact, SomeChit)
                    End If
                End If
                ' check against faction a, if not already detected this turn
                If arrFactionA(a).Detected = False Then
                    If LOSCheck(arrFactionB(b), arrFactionA(a)) = True Then
                        arrFactionA(a).Detected = True
                        ' find this newly targeted chit
                        SomeChit = arrFactionA(a).Chit
                        SomeFact = ptrGameData.Faction_g.Item(arrFactionB(b).OwningFactionKey)
                        IncreaseDetectionOnTarget(SomeFact, SomeChit)
                    End If
                End If
            Next b
        Next a

    End Sub

    Private Function LOSCheck(ByVal detecter As Boiler, ByVal target As Boiler) As Boolean
        ' basic LOS rules calculate LOS range, LOS power, Target Size, Target Terrain LOS cost, detecter terrain LOS cost
        Dim modifiedDistance As Int32
        Dim trueDistance As Int32        ' this is to determine if a unit or objective is outside the possible detection range.
        Dim DetectingTerrainCost As Single
        Dim TargetTerrainCost As Single
        Dim TargetSize As Single
        Try

            ' The actual distance in pixels between the chits
            trueDistance = XYDistance(detecter.Location.X, target.Location.X, detecter.Location.Y, target.Location.Y)

            'If trueDistance < detecter.LosRange Then
            ' modified distance is where we begin trashing the distance!
            modifiedDistance = trueDistance   'well, it has to start somewhere

            ' add each of the distance costs, using the TRUEdistance as starting point
            TargetTerrainCost = modifiedDistance - (modifiedDistance * target.TerrainMod)
            DetectingTerrainCost = modifiedDistance - (modifiedDistance * detecter.TerrainMod)
            modifiedDistance += TargetTerrainCost + DetectingTerrainCost

            ' Modify by Target Size. We're using the MODIFIED distance (coefficient model)
            TargetSize = target.Size
            modifiedDistance += (modifiedDistance - (modifiedDistance * TargetSize))

            ' Modify by Detecting Power, again, using coefficient model 
            modifiedDistance -= ((modifiedDistance * detecter.LosPower) - modifiedDistance)

            If modifiedDistance < detecter.LosRange Then
                Return True
            Else
                Return False
            End If
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
        'End If

    End Function

    Private Function DetectionCheck(ByRef detecter As ChitMember, ByRef target As ChitMember) As Boolean
        '// it uses the distance, LOS POWER, LOS Cost of both target and detecter and size. Yum.
        Try
            Dim TrueDistance As Int32
            Dim modifiedDistance As Int32
            'Dim detectingTerrainCost As Single
            'Dim targetTerrainCost As Single
            'Dim detectPower As Single
            'Dim targetSize As Single
            Dim modifiedLOS As Single

            '// parameters to take into consideration:

            '___PARAMETER________________________________________EFFECT___________________________
            ' terrain cost at both target and detecter          increases modified range
            ' size of target                                    increases detection range
            ' power of detecter                                 modifies detection range

            ' The actual distance in pixels between the chits
            TrueDistance = XYDistance(detecter.Location.X, target.Location.X, detecter.Location.Y, target.Location.Y)

            ' modified distance is where we begin trashing the distance!
            modifiedDistance = TrueDistance   'well, it has to start somewhere

            '// PARAMETER 1: Terrain Costs
            modifiedDistance *= (ptrFMPData.LOSCost(target.Location) + (ptrFMPData.LOSCost(detecter.Location)) - 1) '// we subtract 1 because we don't want to penalize (count "open" twice)
            '// 1.0.2.0 method


            '// we use the detecter power to increase apparent detection range
            modifiedLOS = ((detecter.LOS / 2) * ptrFMPData.PixelsPerOneMile())
            modifiedLOS *= (detecter.LOSPower / 100)
            modifiedLOS *= (target.Size / 100)

            If modifiedDistance < modifiedLOS Then
                Return True
            Else
                Return False
            End If

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.DetectionCheck", ex)
        End Try

    End Function

    Private Sub ResetBoiler()
        ' populate the distance array size
        Dim factAChitCount As Integer
        Dim factBChitCount As Integer
        Dim FactA As cmplib01.Faction
        Dim fukov As String

        For Each fukov In ptrGameData.Faction_g.HT.Keys
            FactA = ptrGameData.Faction_g.Item(fukov)
            Exit For
        Next

        For Each mem As ChitMember In ptrGameData.Chits
            If mem.OwningFaction.Equals(FactA) Then
                factAChitCount += 1
            Else
                factBChitCount += 1
            End If
        Next

        'For Each gcKey In ptrGameData.AllChits.Keys
        '    gc = ptrGameData.AllChits.Item(gcKey)
        '    If gc.OwningFaction = FactA.FactionID Then
        '        '' deal with titanic objects
        '        'If gc.Size >= 10000 Then
        '        '    IncreaseDetectionOnTarget(ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & gc.OwningFaction), gc, False)
        '        'End If
        '        factAChitCount += 1
        '    Else
        '        '' deal with titanic objects here too
        '        'If gc.Size >= 10000 Then
        '        '    IncreaseDetectionOnTarget(FactA, gc, False)
        '        'End If
        '        factBChitCount += 1
        '    End If
        'Next

        ReDim arrFactionA(factAChitCount - 1)
        ReDim arrFactionB(factBChitCount - 1)

    End Sub

    Private Sub PopulateBoiler()
        Dim a As Integer
        Dim b As Integer
        'Dim gcKey As String
        'Dim gc As cmplib01.GroundChitType
        Dim FactA As cmplib01.Faction
        Dim fukov As String

        For Each fukov In ptrGameData.Faction_g.HT.Keys
            FactA = ptrGameData.Faction_g.Item(fukov)
            Exit For
        Next

        For Each mem As ChitMember In ptrGameData.Chits

            If mem.OwningFaction.Equals(FactA) Then
                arrFactionA(a).Chit = mem
                arrFactionA(a).Location = mem.PreciseLocation
                arrFactionA(a).TerrainMod = 1    ' ok. so like... none yet.
                arrFactionA(a).Size = (mem.Size * 0.01)
                arrFactionA(a).LosPower = mem.LOSPower * 0.01
                arrFactionA(a).LosRange = (mem.LOS / 2) * ptrFMPData.PixelsPerOneMile
                arrFactionA(a).Detected = 0 ' not detected really. Nope. Well... not yet.
                arrFactionA(a).OwningFactionKey = ptrGameData.CDGKEY_FACTION & mem.OwningFaction.FactionID
                arrFactionA(a).ZOCRange = (mem.ZOC * ptrFMPData.PixelsPerOneMile) / 2
                a += 1
            Else
                arrFactionB(b).Chit = mem
                arrFactionB(b).Location = mem.PreciseLocation
                arrFactionB(b).TerrainMod = 1    ' ok. so like... none yet.
                arrFactionB(b).Size = (mem.Size * 0.01)
                arrFactionB(b).LosPower = mem.LOSPower * 0.01
                arrFactionB(b).LosRange = (mem.LOS / 2) * ptrFMPData.PixelsPerOneMile
                arrFactionB(b).Detected = 0 ' not detected really. Nope. Well... not yet.                
                arrFactionB(b).OwningFactionKey = ptrGameData.CDGKEY_FACTION & mem.OwningFaction.FactionID
                arrFactionB(b).ZOCRange = (mem.ZOC * ptrFMPData.PixelsPerOneMile) / 2
                b += 1
            End If
        Next

    End Sub

    Private Sub ContactCheck(ByRef unit As ChitMember, ByVal inPhase As Integer)

        Try

            Dim checkOK As Boolean

            For Each target As ChitMember In ptrGameData.Chits

                checkOK = True  '// reset to true

                Select Case unit.Status
                    Case GroundUnitStatus_cgd.Dead : checkOK = False
                    Case GroundUnitStatus_cgd.Engaged : checkOK = False
                    Case GroundUnitStatus_cgd.Not_Deployed : checkOK = False
                End Select

                Select Case target.Status
                    Case GroundUnitStatus_cgd.Dead : checkOK = False
                    Case GroundUnitStatus_cgd.Not_Deployed : checkOK = False
                End Select

                If checkOK = True Then
                    If Not target.OwningFaction.Equals(unit.OwningFaction) Then
                        If XYDistance(target.Location, unit.Location) <= (ptrGameData.combatEngagementRange * 2) Then
                            '// whack any waypoints on both target and not so target
                            If unit.UnitType = GroundChitClass_cgd.Battlegroup Then DirectCast(unit, BattlegroupChit).waypoints.Clear()
                            If target.UnitType = GroundChitClass_cgd.Battlegroup Then DirectCast(target, BattlegroupChit).waypoints.Clear()

                            '// in combat range
                            Createbattle(unit, target, inPhase)
                            SetCombatFlag(unit, target)

                            Dim eFaction As cmplib01.Faction = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & target.OwningFaction.FactionID)
                            Dim fFaction As cmplib01.Faction = ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction.FactionID)
                            IncreaseDetectionOnTarget(eFaction, unit, True)
                            IncreaseDetectionOnTarget(fFaction, target, True)

                            unit.Status = GroundUnitStatus_cgd.Engaged
                            target.Status = GroundUnitStatus_cgd.Engaged

                            '// we throw this in there for good measure
                            detectionHalt = True
                        End If

                    End If
                End If
            Next

        Catch ex As Exception
            HandleException("CampaignerCombatEngine.ContactCheck", ex)
        End Try

    End Sub

    Private Sub Createbattle(ByRef unit As ChitMember, ByRef target As ChitMember, ByVal inPhase As Integer)
        ' creates a battle, or checks to see if the besieged unit is already in combat, or if there is a combat in this
        ' location already? Hmnn. We don't want to add duplicates. Combat is in the location of the initial contact.
        ' This is the battle LOCATION. Attacking and Defending chit have absolutely no meaning, really.
        ' using the rules found in CampaignerCombat.txt, determine if a new combat should be made, or if these
        ' units should be added to an existing combat.
        ' the unit being bumped into is considered the 'defender'. Additional units are marked as defendingsupport or attackingsupport
        ' marks the battle as active in a particular phase

        ' 1 check to see if target unit is already engaged, if so, add 'unit' to the battle targetunit is involved in.
        ' 2 check to see if this combat would be within 'joinCombatRange', from EITHER units' point of view, if so, add them both.
        ' 3 if either '1' or '2' do not apply, create a new combat.
        Dim batt As cmplib01.Battle_2

        ' if there are no battles currently in the list, we don't need any checks we just create a new battle and exit
        If ptrGameData.Battles_g.HT.Count = 0 Then
            AddNewbattle(unit, target, inPhase)
            Exit Sub
        End If

        If target.Status = cmplib01.GroundUnitStatus_cgd.Engaged Then
            Try
                batt = target.battleInvolvedIn
                ' add the new contact to this combat.
                batt.InvolvedChits.add(unit)
                unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
                ' also set this unit to supporting attack or defense, depending on ORIGINAL units.
                SetUnitbattlePosture(unit, batt)
                ' and now, get the hell out!
                Exit Sub
            Catch argEx As ArgumentException
                Exit Sub
            Catch ex As Exception
                'HandleException(c_Module, ex)
                Exit Sub
            End Try
        End If
        ' target is NOT already engaged in combat, check range to existing combats (if we are down here,
        ' we already know there are other combats occuring), if within range, add both units to that combat.
        ' both of these units are considered supporting their faction, whether its attacking or defending (check the units involved 
        ' list to make sure the correct battleposture is set.
        Dim key As String
        Dim distOne As Int16
        Dim distTwo As Int16
        Dim closeDist As Int16
        Dim closestDist As Int16 = 30000
        Dim closestbattleKey As String

        For Each key In ptrGameData.Battles_g.HT.Keys
            batt = ptrGameData.Battles_g.Item(key)
            distOne = XYDistance(unit.Location.X, batt.BattleLocation.X, unit.Location.Y, batt.BattleLocation.Y)
            distTwo = XYDistance(target.Location.X, batt.BattleLocation.X, target.Location.Y, batt.BattleLocation.Y)
            If distOne < distTwo Then
                closeDist = distOne
            Else
                closeDist = distTwo
            End If
            ' we are trying to determine which battle is the closest
            If closeDist < closestDist Then
                closestbattleKey = batt.Key
                closestDist = closeDist
            End If
        Next
        ' determine the distance from the closest unit (to the closest battle)
        If closestDist <= joinCombatDistance Then
            ' add both units to the closest battle, and then set their battle posture
            Try
                batt = ptrGameData.Battles_g.Item(closestbattleKey)
                batt.InvolvedChits.add(unit)
                batt.InvolvedChits.add(target)

                unit.battleInvolvedIn = batt
                target.battleInvolvedIn = batt

                target.Status = cmplib01.GroundUnitStatus_cgd.Engaged
                unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
                ' set the units battle postures accordingly
                SetUnitbattlePosture(unit, batt)
                SetUnitbattlePosture(target, batt)
            Catch ex As Exception
                HandleException(c_Module, ex)
            End Try
        Else
            AddNewbattle(unit, target, inPhase)
        End If

    End Sub

    Private Sub SetCombatFlag(ByRef ptrUnit As ChitMember, ByRef ptrTarget As ChitMember)
        ' finds the owning player and sets his IsInCombat flag.
        Try
            Dim playKey As String
            Dim play As cmplib01.Player


            For Each playKey In ptrGameData.Players.Keys
                play = ptrGameData.Players.Item(playKey)
                play.IsInCombat = True
            Next
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Sub SetCombatFlag(ByRef ptrUnit As ChitMember, ByRef ptrTarget As InstallationChit)

        Try
            Dim playKey As String
            Dim play As cmplib01.Player

            For Each playKey In ptrGameData.Players.Keys
                play = ptrGameData.Players.Item(playKey)
                'TODO: better methodology
                play.IsInCombat = True

            Next
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Sub SetUnitbattlePosture(ByRef unit As ChitMember, ByRef batt As cmplib01.Battle)
        Try
            If unit.OwningFaction.FactionID = batt.AttackingFactionID Then
                unit.currentBattlePosture = BattlePosture_cgd.AttackingSupport
            Else
                unit.currentBattlePosture = BattlePosture_cgd.DefendingSupport
            End If
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Public Sub ResetInvalidWaypoints()
        Try
            For Each mem As ChitMember In ptrGameData.Chits
                If mem.UnitType = GroundChitClass_cgd.Battlegroup Then
                    ResetInvalidWaypoints(DirectCast(mem, BattlegroupChit))
                End If
            Next
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Public Sub ResetInvalidWaypoints(ByRef batt As BattlegroupChit)
        Try
            batt.invalidWaypoint = False
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Public Sub ResetStatus()
        ' resets things like detectedthisturn and such
        '// this needs to be called by the other application if the turn is indeed over!
        Try
            pixelsPerOneMile = ptrFMPData.MapScale.PixelCount / ptrFMPData.MapScale.MilesPerPixelCount

            For Each mem As ChitMember In ptrGameData.Chits

                If mem.UnitType = GroundChitClass_cgd.Battlegroup Then
                    Dim batt As BattlegroupChit = mem

                    '// here we set up the movement value for it if its a battlegroup (transport, etc)
                    batt.calculateProperties()

                    ' apply the GroundUnitStatus rules
                    ResetGroundUnitStatus(batt)
                    '// other properties
                    batt.detectedThisTurn = False
                    batt.currentBattlePosture = cmplib01.BattlePosture_cgd.NoBattle
                    'batt.TotalDistanceMovedThisTurn = 0
                    'batt.invalidWaypoint = False
                    batt.distanceTravelled = 0

                    If batt.historicalPosition Is Nothing Then batt.historicalPosition = New ArrayList
                    batt.historicalPosition.Clear()

                ElseIf mem.UnitType = GroundChitClass_cgd.Objective Then
                    mem.detectedThisTurn = False
                    mem.currentBattlePosture = cmplib01.BattlePosture_cgd.NoBattle
                End If
            Next

        Catch ex As Exception
            HandleException("CampaignerCombatEngineB.ResetStatus", ex)
        End Try

    End Sub

    Private Sub SetEffectiveSpeed(ByRef batt As BattlegroupChit)
        '// the number of pixels this unit can normally travel in one full turn
        '// might not need turn multiplier...

        Try
            If batt.waypoints.Count > 0 Then
                batt.effectiveSpeed = batt.waypoints.item(0).Speed * pixelsPerOneMile * turnMultiplier
                batt.moveRemaining = batt.waypoints.item(0).Speed * pixelsPerOneMile * turnMultiplier
            Else
                batt.effectiveSpeed = 0
                batt.moveRemaining = 0
            End If
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Sub ResetGroundUnitStatus(ByRef mem As ChitMember)
        Select Case mem.Status
            Case GroundUnitStatus_cgd.Regrouping
                mem.Status = GroundUnitStatus_cgd.Regrouped

            Case GroundUnitStatus_cgd.Disarrayed, GroundUnitStatus_cgd.Scattered
                mem.Status = GroundUnitStatus_cgd.Regrouping

            Case GroundUnitStatus_cgd.Dead, GroundUnitStatus_cgd.Not_Deployed, GroundUnitStatus_cgd.Disbanded
                '// keeps the same status

            Case Else
                mem.Status = GroundUnitStatus_cgd.OK
        End Select

    End Sub

    Private Sub AddNewbattle(ByRef unit As ChitMember, ByRef targetUnit As ChitMember, ByVal inPhase As Integer)
        ' if both units are moving, the battle is located between them, if one is not moving, the battle is located at HIS coords
        ' TODO: make the battle at the correct location depending on who is moving, plus other rules that will most likely become
        ' apparent after a beta game is running.
        Dim batt As New cmplib01.Battle_2

        Try
            batt.BattleLocation = LocateNewbattle(unit.Location, targetUnit.Location)
            batt.InvolvedChits.add(unit)
            batt.InvolvedChits.add(targetUnit)

            batt.PhaseActive = inPhase

            batt.BattleName = unit.Name & " vs " & targetUnit.Name
            targetUnit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
            targetUnit.battleInvolvedIn = batt
            unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
            unit.battleInvolvedIn = batt

            ' the unit being bumped into is considered  'defending', the other is 'attacking'
            unit.currentBattlePosture = cmplib01.BattlePosture_cgd.Attacking
            targetUnit.currentBattlePosture = cmplib01.BattlePosture_cgd.Defending

            ' apply the correct faction ids to attacking and defending in the battle for future reference.
            batt.AttackingFactionID = unit.OwningFaction.FactionID
            batt.DefendingFactionID = targetUnit.OwningFaction.FactionID

            ptrGameData.Battles_g.Add(batt, batt.Key)

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Function LocateNewbattle(ByVal pntone As Point, ByVal pnttwo As Point) As Point
        ' new battles are located between the two units (points provided)
        Dim distance As Int32 = (XYDistance(pntone.X, pnttwo.X, pntone.Y, pnttwo.Y) / 2)
        Dim xStr As Single = GetXorYStrength(cmXorY.cmX, pntone.X, pnttwo.X, pntone.Y, pnttwo.Y)
        Dim yStr As Single = GetXorYStrength(cmXorY.cmY, pntone.X, pnttwo.X, pntone.Y, pnttwo.Y)
        Dim location As New Point

        location.X = pntone.X + (distance * xStr)
        location.Y = pntone.Y + (distance * yStr)

        Return location
    End Function

    Private Sub IncreaseDetectionOnTarget(ByRef fact As cmplib01.Faction, ByRef target As ChitMember, Optional ByVal ToKnown As Boolean = True)
        Try

            Select Case target.detectionLevelThisTurn
                Case ChitDetectionLevel_cdl.Undetected
                    target.detectionLevelThisTurn = ChitDetectionLevel_cdl.Detected
                Case ChitDetectionLevel_cdl.Detected
                    target.detectionLevelThisTurn = ChitDetectionLevel_cdl.Spotted
                Case ChitDetectionLevel_cdl.Spotted
                    target.detectionLevelThisTurn = ChitDetectionLevel_cdl.Sighted
                Case ChitDetectionLevel_cdl.Sighted
                    target.detectionLevelThisTurn = ChitDetectionLevel_cdl.Known
                Case ChitDetectionLevel_cdl.Known
                    '// nothing special
                    target.detectionLevelThisTurn = ChitDetectionLevel_cdl.Known
            End Select

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try

    End Sub

    Private Sub handleDetection(ByRef fact As Faction, ByRef target As ChitMember, Optional ByVal toknown As Boolean = True)
        Try
            ' if the chit was already detected this turn, only change it if toKnown==true
            'Dim histo As HistoricalEntry = target.playbackEntries.item(ptrGameData.ElapsedTime)

            '// we're here because we've been detected.
            target.detectedThisPhase = True

            If toknown Then
                target.detectionLevelThisTurn = ChitDetectionLevel_cdl.Known 'histo.detectionStatus = ChitDetectionLevel_cdl.Known
            Else
                '// target was not previously detected
                '// 1.0.2.0
                If target.detectionLevelThisTurn = ChitDetectionLevel_cdl.Undetected Then

                    '// check for a pattern of detected, not detected, detected, not detected. Its not a "halt" if that pattern exists

                    detectionHalt = True
                End If

                target.detectionLevelThisTurn += _LOSDegredationAmount
                If target.detectionLevelThisTurn > ChitDetectionLevel_cdl.Known_high Then target.detectionLevelThisTurn = ChitDetectionLevel_cdl.Known_high

                target.detectedThisTurn = True
                If toknown Then target.detectionLevelThisTurn = ChitDetectionLevel_cdl.Known
            End If

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Private Sub DecreaseDetectionForUnspotted()
        For Each mem As ChitMember In ptrGameData.Chits

            '// not for titanic
            If mem.Size <= 1500 Then
                If Not mem.Status = GroundUnitStatus_cgd.Dead Then mem.detectionLevelThisTurn -= _LOSDegredationAmount
                If mem.detectionLevelThisTurn < ChitDetectionLevel_cdl.Undetected Then mem.detectionLevelThisTurn = ChitDetectionLevel_cdl.Undetected
            End If
        Next

    End Sub

    Public Sub ResetDeploymentValues(ByRef ptrGame As CampaignerGameData)
        ' resets the deploymentzone amount available in this turn.
        Dim dep As cmplib01.DeploymentZone
        Dim depKey As String

        Try
            For Each depKey In ptrGame.DeploymentZones_g.HT.Keys
                dep = ptrGame.DeploymentZones_g.HT.Item(depKey)
                dep.PointsDeployedThisTurn = 0
            Next
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

#Region "Implemented Methods"
    Public Sub OpenCombatEngine(ByVal filePath As String) Implements ICombatEngine.ICombatEngine.OpenCombatEngine

    End Sub

    Public Sub SaveCombatEngine(ByVal filePath As String) Implements ICombatEngine.ICombatEngine.SaveCombatEngine

    End Sub

    Public Sub ShowPostCombatWindow() Implements ICombatEngine.ICombatEngine.ShowPostCombatWindow

    End Sub

    Public Sub ShowPreCombatWindow() Implements ICombatEngine.ICombatEngine.ShowPreCombatWindow

    End Sub
#End Region

#Region "After Combat"

    Public Sub ApplyCombatResults(ByRef GameData As cmplib01.CampaignerGameData)
        ' checks each battle and moves any units that need to be moved and reassigns objectives to victorous units.
        Dim key As String
        Dim batt As cmplib01.Battle

        ptrGameData = GameData

        If GameData.Battles_g.HT.Count > 0 Then
            ' step through each battle
            For Each key In GameData.Battles_g.HT.Keys
                batt = GameData.Battles_g.Item(key)

                For Each mem As ChitMember In batt.InvolvedChits
                    If mem.Status = GroundUnitStatus_cgd.Dead Then
                        '// doin' nuthin'
                    Else
                        Select Case mem.UnitType
                            Case GroundChitClass_cgd.Battlegroup
                                UnitbattleResult(mem, batt)
                            Case GroundChitClass_cgd.Objective
                                ObjectivebattleResult(mem, batt, GameData)
                        End Select
                    End If
                Next

            Next key
        Else
            Exit Sub
        End If

    End Sub

    Private Sub UnitbattleResult(ByRef unit As BattlegroupChit, ByVal batt As cmplib01.Battle)
        ' used to apply the correct result to a unit
        Dim battlelocation As Point = batt.BattleLocation

        ' apply the battleresult to this unit, this sets the correct battle result
        AssignbattleResultToGroundChit(unit, batt)

        '// status will be manually assigned, or an option can be set for it.
        Select Case unit.battleResult
            Case cmplib01.UnitBattleResult_cgd.Defeat
                KnockUnitBack(unit, ptrGameData.combatEngagementRange, battlelocation)
                '                unit.Status = cmplib01.GroundUnitStatus_cgd.Regrouping
                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
            Case cmplib01.UnitBattleResult_cgd.Draw
                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
                KnockUnitBack(unit, ptrGameData.combatEngagementRange / 2, battlelocation)
            Case cmplib01.UnitBattleResult_cgd.MarginalDefeat
                KnockUnitBack(unit, ptrGameData.combatEngagementRange * 0.6, battlelocation)
                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
            Case cmplib01.UnitBattleResult_cgd.MarginalVictory
                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
            Case cmplib01.UnitBattleResult_cgd.Victory
                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
        End Select

    End Sub

    Private Sub ObjectivebattleResult(ByRef obj As InstallationChit, ByVal batt As cmplib01.Battle, ByRef gameData As CampaignerGameData)
        ' used to apply the correct result to an objective and change ownership

        AssignbattleResultToGroundChit(obj, batt)

        ' apply the battleresult to this objective, which sets the correct battle result.
        ' any victory for the attacker will take ownership of the objective
        Select Case obj.battleResult
            Case cmplib01.UnitBattleResult_cgd.Defeat
                ' give the objective to the attacker
                obj.OwningFaction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
                '// remove the installation from the attacking factions detection
                '// and add it to the defending faction's detection!
                'Dim deffact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.DefendingFactionID)
                'Dim attfact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
                'Dim detKey As String
                'For Each detKey In attfact.HTChitDetection.Keys
                '    Debug.WriteLine(detKey)
                'Next

            Case cmplib01.UnitBattleResult_cgd.MarginalDefeat
                obj.OwningFaction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
                'Dim deffact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.DefendingFactionID)
                'Dim attfact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
                'Dim detKey As String
                'For Each detKey In attfact.HTChitDetection.Keys
                '    Debug.WriteLine(detKey)
                'Next

        End Select

    End Sub

    Private Sub KnockUnitBack(ByRef unit As BattlegroupChit, ByVal distance As Int16, ByVal fromLocation As Point)
        ' if a unit is knocked back into a terrain it can't move into, it should be DESTROYED!!! See CampaignerCombat.txt
        Dim xStr As Single = GetXorYStrength(cmXorY.cmX, unit.Location.X, fromLocation.X, unit.Location.Y, fromLocation.Y)
        Dim yStr As Single = GetXorYStrength(cmXorY.cmY, unit.Location.X, fromLocation.X, unit.Location.Y, fromLocation.Y)
        Dim newLocation As New Point(unit.Location.X, unit.Location.Y)

        'reverse the values so they move in the correct direction
        xStr = xStr * -1
        yStr = yStr * -1

        newLocation.X = unit.PreciseLocation.X + (distance * xStr)
        newLocation.Y = unit.PreciseLocation.Y + (distance * yStr)
        unit.PreciseLocation = newLocation

    End Sub

    Private Sub AssignbattleResultToGroundChit(ByRef gChit As ChitMember, ByRef batt As cmplib01.Battle)
        ' HACK: There is a better way to do this than brute force... figure it out.

        Select Case batt.BattleResult
            Case BattleResult_cgd.AttackerVictory
                If gChit.OwningFaction.FactionID.Equals(batt.AttackingFactionID) Then
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.Victory
                Else
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.Defeat
                End If
            Case BattleResult_cgd.AttackerMarginalVictory
                If gChit.OwningFaction.FactionID.Equals(batt.AttackingFactionID) Then
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                Else
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                End If
            Case BattleResult_cgd.Draw
                If gChit.OwningFaction.FactionID.Equals(batt.AttackingFactionID) Then
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                Else
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                End If
            Case BattleResult_cgd.DefenderVictory
                If gChit.OwningFaction.FactionID.Equals(batt.AttackingFactionID) Then
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.Defeat
                Else
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.Victory
                End If
            Case BattleResult_cgd.DefenderMarginalVictory
                If gChit.OwningFaction.FactionID.Equals(batt.AttackingFactionID) Then
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                Else
                    gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                End If
            Case Else

        End Select

        Exit Sub

        Select Case gChit.currentBattlePosture
            Case cmplib01.BattlePosture_cgd.Attacking
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Victory
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Defeat
                    Case cmplib01.BattleResult_cgd.Draw : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.AttackingIndirectSupport
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Defeat
                    Case cmplib01.BattleResult_cgd.Draw : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.AttackingReserve
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.Draw : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.AttackingSupport ' same as indirect support
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Defeat
                    Case cmplib01.BattleResult_cgd.Draw : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.Defending
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Defeat
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Victory
                    Case cmplib01.BattleResult_cgd.Draw : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.DefendingIndirectSupport
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.Draw : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.DefendingReserve
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.Draw : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.DefendingSupport ' same as indirect support
                Select Case batt.BattleResult
                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.battleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
                    Case cmplib01.BattleResult_cgd.Draw : gChit.battleResult = cmplib01.UnitBattleResult_cgd.Draw
                End Select
            Case cmplib01.BattlePosture_cgd.NoBattle
                gChit.battleResult = cmplib01.UnitBattleResult_cgd.NoBattle
        End Select
    End Sub

#End Region

#Region "Properties"

    Public Property UsesContactCombat() As Boolean Implements ICombatEngine.ICombatEngine.UsesContactCombat
        Get
            Return True
        End Get
        Set(ByVal Value As Boolean)

        End Set
    End Property

    Public Property UsesPrecombatWindow() As Boolean Implements ICombatEngine.ICombatEngine.UsesPrecombatWindow
        Get
            Return False
        End Get
        Set(ByVal Value As Boolean)

        End Set
    End Property

    Public Property UsesRangedCombat() As Boolean Implements ICombatEngine.ICombatEngine.UsesRangedCombat
        Get
            Return False
        End Get
        Set(ByVal Value As Boolean)

        End Set
    End Property

#End Region

    Public ReadOnly Property PostCombatWindow() As System.Windows.Forms.UserControl Implements ICombatEngine.ICombatEngine.PostCombatWindow
        Get
            Return Nothing
        End Get
    End Property

    Public Property UsesPostCombatWindow() As Boolean Implements ICombatEngine.ICombatEngine.UsesPostCombatWindow
        Get
            Return True
        End Get
        Set(ByVal value As Boolean)

        End Set
    End Property

    Public ReadOnly Property PreCombatWindow() As System.Windows.Forms.UserControl Implements ICombatEngine.ICombatEngine.PreCombatWindow
        Get
            Return Nothing
        End Get
    End Property

    Public Property FlexMap() As FMPLib01.FlexMapData Implements ICombatEngine.ICombatEngine.FlexMap
        Get
            Return ptrFMPData
        End Get
        Set(ByVal value As FMPLib01.FlexMapData)
            ptrFMPData = value
        End Set
    End Property

    Public ReadOnly Property CombatEngineID() As ICombatEngine.CombatEngineIdentifier Implements ICombatEngine.ICombatEngine.CombatEngineID
        Get
            Return CombatEngineIdentifier.Conquest
        End Get
    End Property

    Public ReadOnly Property Author() As String Implements ICombatEngine.ICombatEngine.Author
        Get
            Return "Racingspider Games, LLC"
        End Get
    End Property

    Public ReadOnly Property Notes() As String Implements ICombatEngine.ICombatEngine.Notes
        Get
            Return "This is the conquest combat engine."
        End Get
    End Property

    Private Sub ConquestCombat()
        '// this will handle the combats
        Try
            For Each battKey As String In ptrGameData.Battles_g.HT.Keys
                Dim batt As Battle_2 = ptrGameData.Battles_g.Item(battKey)

                For Each mem As ChitMember In batt.InvolvedChits
                    HandleGroup(mem)
                Next

                '// put a random explosion in.


            Next
        Catch ex As Exception

        End Try
    End Sub

    Private Sub HandleGroup(ByRef chit As ChitMember)
        Try
            Select Case chit.UnitType
                Case GroundChitClass_cgd.Battlegroup

                    For Each mem As ChitMember In DirectCast(chit, BattlegroupChit).members
                        HandleGroup(mem)
                    Next

                Case GroundChitClass_cgd.Objective

                Case GroundChitClass_cgd.Token

                Case GroundChitClass_cgd.Unit
                    RandomlyBlastUnit(chit)
            End Select
        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Private Sub RandomlyBlastUnit(ByRef chit As ChitMember)
        '// test. Hits a unit for a random amount of damage (HLT)
        '// get the HLT attribute
        Try
            Dim hlt As Integer = GetUnitHealth(chit)
            Dim x As Integer
            x = randy.Next(0, 5)
            hlt -= x

            SetUnitHealth(chit, hlt)

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Private Function GetUnitHealth(ByVal chit As ChitUnitTypeMember) As Integer
        Try
            Dim health As String = ""
            For Each s As String In chit.Attributes
                If s.StartsWith("HLT:") Then
                    health = s.Replace("HLT:", "")
                    Exit For
                End If
            Next

            Return CInt(health)

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Function

    Private Sub SetUnitHealth(ByRef chit As ChitUnitTypeMember, ByVal value As Integer)
        Try
            For Each s As String In chit.Attributes
                If s.StartsWith("HLT:") Then
                    chit.Attributes.Remove(s)
                    chit.Attributes.Add("HLT: " & value, "HLT: " & value)
                End If
            Next

        Catch ex As Exception
            HandleException(c_Module, ex)
        End Try
    End Sub

    Public ReadOnly Property ReplayEvents() As Microsoft.VisualBasic.Collection Implements ICombatEngine.ICombatEngine.ReplayEvents
        Get
            Return Nothing
        End Get
    End Property

    Public Sub PrepareCampaign(ByRef gamedata As Object) Implements ICombatEngine.ICombatEngine.PrepareCampaign
        Try

            ptrGameData = DirectCast(gamedata, CampaignerGameData)
            PreGameDPContest()


        Catch ex As Exception

        End Try
    End Sub
End Class
